#include <stdio.h>
#include <libpq-fe.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

//tipo ip é: 1 para ipv4 e 2 para ipv6
//nat é: 1 para interno e 2 para externo

//fazer uma função para saber se as variaveis que estão na URL são unicas.
char query [150];
PGconn *conn = NULL;	
PGresult *result;
FILE *file;	
char* serverIp;
//bind rndc.conf 7 linha..

//functions
char* searchIpHost(char * hostName);//ok!
int searchIdHost(char* hostName);//ok!
int searchIdUser(char* email);//ok!
int update(int idHost,int idUser,char *currentIp,char *lastIp, char *email, char *password);//ok!
int authenticateUser(char *email, char *password);//ok!
int addUser(char *email, char *password, char *userName, int userType);//ok!
int addHost(int userId, char *hostName, int nat, char *ip, int ipType, char *email, char *password);//ok!
char* getValue(char *c,char *v);//ok!
int validateIp(char *c);//ok!
char *getTime();
void resultStatus(int result);
int restartServer();
int getNat(char *hostName);//mudar c para hostname
int getTypeIp(char *hostName);
char* getIp();//pega o ip do servidor
int enableRegister();
int removeHost(int idHost, char *email, char *password);

//delete from tabela_host where nome_host = '%s'

//corrigir os bugs do sistema




int main(){

	int serviceType,r,nat,id;
	char lastIp[41];	
	char *aux;
	char *aux2 = malloc(200);
	serverIp = getIp();
	const char* string_connection = "host=localhost port=5432 dbname=TESTE user=postgres password=admin";
	printf("Content-type: text/plain\n\n<html>\n<head>\n</head>\n<body>\n");
	conn = PQconnectdb(string_connection);
	if (PQstatus(conn) != CONNECTION_OK){
		printf("log=Problem in connecting '%s', error found ='%s'\n",string_connection,PQerrorMessage(conn));
		if (conn != NULL) PQfinish(conn);
		return (1);
	}
	
	aux2 = getenv("QUERY_STRING");
	serviceType = atoi(getValue(aux2,"serviceType"));
	switch(serviceType){
		case (1):
			//https://127.0.0.1/cgi-bin/si.cgi?serviceType=1&email=robertosicabral@gmail.com&password=1&hostName=real&userName=rbCabral&nat=1&ip=192.0.1.2&ipType=1
			if(getNat(getValue(aux2,"hostName"))==2){
				strcpy(lastIp,getenv("REMOTE_ADDR"));
			}else{
				strcpy(lastIp,getValue(aux2,"ip"));
			}
			id = searchIdHost(getValue(aux2,"hostName"));
			if(validateIp(lastIp) && id){
				if(update(id,searchIdUser(getValue(aux2,"email")),lastIp,searchIpHost(getValue(aux2,"hostName")),getValue(aux2,"email"),getValue(aux2,"password"))==1){
					printf("atualizado com sucesso\n");
				}
			}else{
					printf("Ip invalido\n");
			} 
			break;
		case (2):
			//https://127.0.0.1/cgi-bin/si.cgi?serviceType=2&email=robertosicabral@gmail.com&password=1&hostName=real&userName=rbCabral&nat=1&ip=192.0.1.2&ipType=1
			strcpy(lastIp,getenv("REMOTE_ADDR"));
			nat=atoi(getValue(aux2,"nat"));
			if(nat==1){
				strcpy(lastIp,getValue(aux2,"ip"));
			}
			r = addHost(searchIdUser(getValue(aux2,"email")),getValue(aux2,"hostName"),nat,lastIp,atoi(getValue(aux2,"ipType")),getValue(aux2,"email"),getValue(aux2,"password"));
			if(r==0){
				printf("Erro de autentiticação\n");
			}else if (r==-1){
				printf("Host ja existe\n");
			}else if (r==-2){
				printf("Ip invalido\n");
			}else{
				printf("Host Cadastrado com Sucesso\n");
			}
			break;	
		case (3):
			//https://127.0.0.1/cgi-bin/si.cgi?serviceType=3&email=arthur@gmail.com&password=11&userName=Arthur&typeUser=3
			if(enableRegister()==1){
				r = addUser(getValue(aux2,"email"),getValue(aux2,"password"),getValue(aux2,"userName"),atoi(getValue(aux2,"typeUser")));
				if(r==1){
					printf("Cadastrado com Sucesso\n");
				}else{
					printf("Email já cadastrado\n");
				}
			}else{
				printf("O cadastro de novos clientes não está ativo\n");
			}
			break;
		case (4):
			//https://127.0.0.1/cgi-bin/si.cgi?hostName=test&serviceType=4
			aux = searchIpHost(getValue(aux2,"hostName"));
			if(aux!=NULL){
				printf("ip=%s\n",aux);
				free(aux);
			}
			break;
		case (5):
			//https://127.0.0.1/cgi-bin/si.cgi?serviceType=5&email=robertosicabral@gmail.com&password=1
			r = authenticateUser(getValue(aux2,"email"),getValue(aux2,"password"));
			if (r==-2){
				printf("Email não cadastrado\n");
			}else if (r==-1){
				printf("Email ou senha não cadastrado\n");
			}else if (r==1){
				printf("Autenticado com Sucesso\n");
			}
			break;
		case (6):
			//https://127.0.0.1/cgi-bin/si.cgi?serviceType=6&userName=qqq-gmail.com
			printf("%d",searchIdUser(getValue(aux2,"userName")));
			break;
		case (7):
			//https://127.0.0.1/cgi-bin/si.cgi?serviceType=7&email=robertosicabral@gmail.com&password=1&hostName=ttt
			printf("%d",removeHost(searchIdHost(getValue(aux2,"hostName")),getValue(aux2,"email"),getValue(aux2,"password")));
			break;
		case (8):
			//https://127.0.0.1/cgi-bin/si.cgi?serviceType=8
			printf("ok\n");
			break;
		default:
			printf("FAIL\n");
			break;
	
	
	}
	printf("</body>\n</html>\n");	
	return 0;	
}


char* searchIpHost(char * hostName){//ok---apenas colocar logs
	char *ipHost;
	sprintf(query, "select count (ip) from tabela_host where nome_host = '%s'",hostName);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==0||PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("log=Host invalido\n");
		PQclear(result);
		return NULL;
	}
	PQclear(result);
	sprintf(query, "SELECT ip FROM tabela_host WHERE nome_host = '%s'", hostName);
	result = PQexec(conn, query);
	if (PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("log=Error in search\n");
		PQclear(result);
		return NULL;
	}
	ipHost = (char*)malloc(strlen(PQgetvalue(result, 0, 0))*sizeof(char));
	strcpy(ipHost,PQgetvalue(result, 0, 0));
	PQclear(result);
	return ipHost;
}

int searchIdHost(char* hostName){//ok---apenas colocar logs
	sprintf(query, "select count (id_host) from tabela_host where nome_host = '%s'",hostName);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==0||PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("Host invalido\n");
		PQclear(result);
		return 0;
	}
	sprintf(query, "SELECT id_host FROM tabela_host WHERE nome_host = '%s'", hostName);
	result = PQexec(conn, query);
	if (PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("Error in search\n");
		PQclear(result);
		return -1;
	}
	return atoi(PQgetvalue(result, 0, 0));
}	

int searchIdUser(char* email){//ok---apenas colocar logs
	sprintf(query, "select count (id_usuario) from usuario where email = '%s'",email);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==0||PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("User invalido\n");//traduzir
		PQclear(result);
		return 0;
	}
	sprintf(query, "SELECT id_usuario FROM usuario WHERE email = '%s'",email);
	result = PQexec(conn, query);
	if (PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("Error in search\n");
		PQclear(result);
		return -1;
	}
	return atoi(PQgetvalue(result, 0, 0));
}	

int update(int idHost,int idUser,char *currentIp,char *lastIp, char *email, char *password){/*olhar se já esta atualizado reiniciar servidor*/
	int ok=0;
	if(authenticateUser(email,password)!=1){
		printf("Erro autenticação\n");
		return 0;
	}
	
	if(validateIp(currentIp)==0){
		printf("Erro Ip atual\n");
		return 0;
	}
	if(validateIp(lastIp)==0){
		printf("Erro Ip antigo\n");
		return 0;
	}
	
	if(strcmp(lastIp,currentIp)!=0){
		sprintf(query,"INSERT INTO tabela_atualizacao (id_usuario, data_hora, ipatual, ipantigo, id_host) VALUES ('%d', '%s', '%s', '%s', '%d')", idUser,getTime(),currentIp,lastIp,idHost);
		result = PQexec(conn, query);
		if(!result){
			printf("Error in update\n");
			PQclear(result);
			return -1;
		}
		PQclear(result);
		ok=1;
	}
	sprintf(query,"UPDATE tabela_host SET ip = '%s' , data_hora = '%s' where id_host = '%d'",currentIp,getTime(),idHost);
	result = PQexec(conn, query);
	if(!result){
		printf("Error in update\n");
		PQclear(result);
		return -1;
	}
	PQclear(result);
	ok=1;
	if(ok==1){
		if(restartServer()==0){
			printf("Error in update\n");
		}	
	}
	return 1;
}

int authenticateUser(char *email, char *password){
	sprintf(query, "select count (email) from usuario where email = '%s'",email);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==0 || PQresultStatus(result) != PGRES_TUPLES_OK){
		resultStatus(PQresultStatus(result));
		PQclear(result);
		return -2;
	}
	sprintf(query, "select email,senha from usuario where email = '%s'", email);//lembrar
	result = PQexec(conn, query);
	if (PQresultStatus(result) != PGRES_TUPLES_OK){
		resultStatus(PQresultStatus(result));
		PQclear(result);
		return 0;
	}
	if(strcmp(PQgetvalue(result, 0, 0),email)==0 && strcmp(PQgetvalue(result, 0, 1),password)==0){
		resultStatus(PQresultStatus(result));
		PQclear(result);
		return 1;
	}else{
		resultStatus(PQresultStatus(result));
		PQclear(result);
		return -1;
	}
	
}
	
int addUser(char *email, char *password, char *userName, int userType){
	sprintf(query, "select count (email) from usuario where email = '%s'",email);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==1){
		PQclear(result);
		return -1;
	}
	PQclear(result);
	sprintf(query, "insert into usuario (email,nome_usuario,senha,id_tipo_usuario) values ('%s','%s','%s','%d')", email,userName,password,userType);
	result = PQexec(conn, query);
	resultStatus(PQresultStatus(result));
	PQclear(result);
	return 1;
}

int addHost(int userId, char *hostName, int nat, char *ip, int ipType, char *email, char *password){
	if(authenticateUser(email,password)!=1){
		return 0;
	}
	sprintf(query, "select count (nome_host) from tabela_host where nome_host = '%s'",hostName);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==1){
		PQclear(result);
		resultStatus(PQresultStatus(result));
		return -1;
	}
	PQclear(result);
	if(validateIp(ip)==0){
		return -2;
	}
	sprintf(query, "insert into tabela_host (id_usuario,nome_host,data_hora,nat,ip,tipo_ip) values ('%d','%s','%s','%d','%s','%d')",userId,hostName,getTime(),nat,ip,ipType);
	result = PQexec(conn, query);
	resultStatus(PQresultStatus(result));
	PQclear(result);
	return 1;
}

char* getValue(char *c,char *v){
	char aux[50];
	char aux2[50];
	char *res;
	int i=0,p=0;
	while(c[i]!='\0'){
		if(c[i]!='='){
			aux[p++]=c[i];
		}
		if(c[i]=='='){
			aux[p++]='\0';
			p=0;
			if(strcmp(v,aux)==0){
				i++;
				while(c[i]!='&'&&c[i]!='\0'){
					aux2[p++]=c[i];
					i++;
				}
				aux2[p++]='\0';
				res = (char*)malloc(p*sizeof(char));
				strcpy(res,aux2);
				return res;
			}else{
				while(c[i]!='&')i++;
			}
		}
		i++;	
	}
	return NULL;
}

int validateIp(char *c){
	int i=0,p=0,cont=0;
	char aux [50];
	if(strlen(c)<7){
		return 0;
	}
	while(c[i]!='\0'){
		while(c[i] != '.' && c[i] != '\0'){
			aux[p++]=c[i];
			i++;
		}
		if(c[i]=='.')cont++;
		i++;
		if(cont==4){
			return 0;
		}
		aux[p]='\0';
		p=0;
		if(atoi(aux)<256){
			continue;
		}else{
			return 0;
		}
	}
	return 1;
}

char *getTime(){
	struct tm *local;
	time_t t;
	t=time(NULL);
	local=localtime(&t);
	char *aux = (char*)malloc(25*sizeof(char));
	sprintf(aux,"%d-%d-%d %d:%d:%d",local->tm_year+1900,local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min,local->tm_sec);
	aux[strlen(aux)+1]='\0';
	return aux;
}

void resultStatus(int result){
	file = fopen("/home/roberto/Servidor.log", "a");
	switch(result){
		case (PGRES_EMPTY_QUERY):
			fprintf(file,"The string sent to the server was empty.\n");
			break;
		case (PGRES_COMMAND_OK):
			fprintf(file,"Successful completion of a command returning no data.\n");
			break;
		case (PGRES_TUPLES_OK):
			fprintf(file,"Successful completion of a command returning data.\n");
			break;
		case (PGRES_COPY_OUT):
			fprintf(file,"Copy Out (from server) data transfer started.\n");
			break;			
		case (PGRES_COPY_IN):
			fprintf(file,"Copy In (to server) data transfer started.\n");
			break;
		case (PGRES_BAD_RESPONSE):
			fprintf(file,"The server's response was not understood.\n");
			break;
		case (PGRES_NONFATAL_ERROR):
			fprintf(file,"A nonfatal error (a notice or warning) occurred.\n");
			break;
		case (PGRES_FATAL_ERROR):
			fprintf(file,"A fatal error occurred.\n");
			break;
		default :
			fprintf(file,"unidentified error\n");
			break;
	}	
	fclose(file);
}

int restartServer(){
	int cont,i;
	char *l = malloc(20),*buf = malloc(20);
	sprintf(query, "select count (ip) from tabela_host");
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==0||PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("Sem hosts cadastrados\n");
		PQclear(result);
		return 0;
	}
	file = fopen("/etc/bind/db.local", "r");
	fscanf(file,"%s",l);
	fclose(file);
	for(i=1;l[i]!='\0';i++){
		l[i-1]=l[i];
	}
	l[i-1]='\0';
	file = fopen("/etc/bind/db.local", "w");
	cont=atoi(PQgetvalue(result, 0, 0));
	PQclear(result);
	sprintf(query, "SELECT ip,nome_host FROM tabela_host");
	result = PQexec(conn, query);
	fprintf(file,";%d\n$TTL	604800\n",atoi(l)+1);
	fprintf(file,"@	IN	SOA	ns.quixada.ufc.br. roberto.quixada.ufc.br. (\n");
	fprintf(file,"				%d		; Serial\n",atoi(l)+1);
	fprintf(file,"			 	604800		; Refresh\n");
	fprintf(file,"			  	0086400		; Retry\n");
	fprintf(file,"				0849560		; Expire\n");
	fprintf(file,"			 	604800 )	; Negative Cache TTL\n;\n");
	fprintf(file,"@	IN	NS	ns.quixada.ufc.br.\n");
	fprintf(file,"@	IN	A	%s\n",serverIp);
	for(i=0;i<cont;i++){
		fprintf(file,"%s	IN	A	%s\n",PQgetvalue(result, i, 1),PQgetvalue(result, i, 0));
	}
	fclose(file);
	if (PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("Error in search\n");
		PQclear(result);
		return 0;
	}
	
	PQclear(result);
	system("/home/roberto/./test");
	return 1;
}

int getNat(char *hostName){
	sprintf(query, "select count (nat) from tabela_host where nome_host = '%s'",hostName);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))!=1){
		PQclear(result);
		resultStatus(PQresultStatus(result));
		return -1;
	}	
	PQclear(result);
	sprintf(query, "select nat from tabela_host where nome_host = '%s'",hostName);
	result = PQexec(conn, query);
	if (PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("Error in search of nat\n");
		PQclear(result);
		return -2;
	}
	return atoi(PQgetvalue(result, 0, 0));
}

int getTypeIp(char *hostName){
	sprintf(query, "select count (tipo_ip) from tabela_host where nome_host = '%s'",hostName);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))!=1){
		PQclear(result);
		resultStatus(PQresultStatus(result));
		return -1;
	}	
	PQclear(result);
	sprintf(query, "select tipo_ip from tabela_host where nome_host = '%s'",hostName);
	result = PQexec(conn, query);
	if (PQresultStatus(result) != PGRES_TUPLES_OK){
		printf("Error in search of Type IP\n");
		PQclear(result);
		return -2;
	}
	return atoi(PQgetvalue(result, 0, 0));
}

char* getIp(){
	char *line;
	line = (char*)malloc(sizeof(char)*20);
	int i,r=0,j;
	file = fopen("/home/roberto/conf", "r");
	fscanf(file, "%[^\n]", line);
	i=0;
	while(line[i]!='='){
		i++;
	}
	j=i+2;
	while(line[j]!=';'){
		line[r++]=line[j];
		j++;
	}
	line[r++]='\0';
	return line;
}

int enableRegister(){
	char *line;
	size_t len= 100;
	line = (char*)malloc(sizeof(char)*len);
	int i,r=0,j;
	file = fopen("/home/roberto/conf", "r");
	if(!file){
		return -1;
	}
	getline(&line, &len, file);
	getline(&line, &len, file);
	i=0;
	while(line[i]!='='){
		i++;
	}
	j=i+2;
	while(line[j]!=';'){
		line[r++]=line[j];
		j++;
	}
	line[r++]='\0';
	return atoi(line);
}

int removeHost(int idHost,char *email, char *password){
	if(authenticateUser(email,password)!=1){
		return 0;
	}
	sprintf(query, "select count (id_host) from tabela_host where id_host = '%d'",idHost);
	result = PQexec(conn, query);
	if(atoi(PQgetvalue(result, 0, 0))==0){
		PQclear(result);
		resultStatus(PQresultStatus(result));
		return -1;
	}
	PQclear(result);
	sprintf(query, "delete from tabela_atualizacao where id_host = '%d'",idHost);
	result = PQexec(conn, query);
	PQclear(result);
	sprintf(query, "delete from tabela_host where id_host = '%d'",idHost);
	result = PQexec(conn, query);
	PQclear(result);
	return 1;
}

